package com.liachen.stock.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.liaochong.myexcel.core.DefaultExcelBuilder;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.liachen.common.constant.Constant;
import com.liachen.common.util.ToolsUtil;
import com.liachen.stock.entity.Notice;
import com.liachen.stock.entity.NoticeFile;
import com.liachen.stock.entity.Report;
import com.liachen.stock.entity.ValuationReport;
import com.liachen.stock.entity.ZsStockInfo;
import com.liachen.stock.entity.ZsStockPool;
import com.liachen.stock.ext.ZsxgService;
import com.liachen.stock.service.ReportService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 下载研报
 *
 * @author d85v8h9 chen.liang
 * @date 2021/4/2 10:59
 * @since V1.0
 */
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private ZsxgService zsxgService;
    protected HttpServletResponse response;
    @Override
    public void downLoadReport() throws IOException {
        List<Report> reportList = zsxgService.getReportList();

        reportList.stream().forEach(this::downLoanReport);
    }

    private void downLoanReport(Report report) {
        String star = "";
        if (report.isStarAuthor()) {
            star = "@";
        }

        try {
            String reportName = String.format("%s[%s][%s].pdf", star, report.getIdx().substring(0,8), report.getHighlightTitle());
            String path = String.format("%s\\%s\\研报", Constant.COMPANY_PATH, report.getCompanyName());
            File reportFile = new File(String.format("%s\\%s", path, reportName));
            if (!reportFile.exists() && StringUtils.isNotBlank(report.getUrl())) {
                Request request = new Request.Builder().url(report.getUrl()).build();
                Response response = ToolsUtil.getClient().newCall(request).execute();
                ToolsUtil.mkdir(path);
                FileOutputStream outFile =
                        new FileOutputStream(reportFile);
                outFile.write(response.body().bytes());
                outFile.close();
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void downLoadReportByCodes(String codes) throws IOException {
        List<String> codeList = Splitter.on(",").splitToList(codes);
        codeList.forEach(code -> {
            try {
                List<Report> reportList = zsxgService.getReportListByCode(code);
                reportList.stream().forEach(this::downLoanReport);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    public void downLoadNotice() throws IOException {
        List<Notice> noticeList = zsxgService.getNoticeList();
        noticeList.stream().forEach(this::downLoanReportNotice);
    }

    private void downLoanReportNotice(Notice notice) {
        if (notice.getPdfCount() > 1) {
            try {
                List<NoticeFile> noticeFiles = zsxgService.getNoticeUrlList(notice.getId());
                noticeFiles.stream().forEach(noticeFile -> downLoadNoticeByUrl(noticeFile.getUrl(), noticeFile.getNoticeName(), noticeFile.getName()));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }

        } else {
            downLoadNoticeByUrl(notice.getUrl(), notice.getNoticeName(), notice.getName());
        }
    }

    @Override
    public void downLoadNoticeByCodes(String codes) {
        List<String> codeList = Splitter.on(",").splitToList(codes);
        codeList.forEach(code -> {
            try {
                List<Notice> noticeList = zsxgService.getNoticeListByCode(code);
                noticeList.stream().forEach(this::downLoanReportNotice);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    public void downloadValuationReport(String poolId) throws IOException {
        ZsStockPool zsStockPool = zsxgService.getStockFromPool(poolId);
        List<ValuationReport> reportList = Lists.newArrayList();
        List<ValuationReport> sortedList;
        if (Objects.nonNull(zsStockPool)) {
            zsStockPool.getStockList().forEach(stock -> {
                try {
                    ZsStockInfo stockInfo = zsxgService.getStockInfo(stock.getCode());
                    ValuationReport valuationReport = convertFrom(stockInfo);
                    if (valuationReport.getBuyPoint() != 0 && !valuationReport.getShowNetProfit().equals("--")) {
                        reportList.add(valuationReport);
                    }
                    log.info("valuationReport = {}",JSONObject.toJSONString(valuationReport));
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            });
            sortedList = reportList.stream().sorted(Comparator.comparing(ValuationReport::getLocationBuyPoint)).collect(Collectors.toList());
            Workbook workbook = DefaultExcelBuilder.of(ValuationReport.class).build(sortedList);
            ToolsUtil.mkdir(Constant.VALUATION_PATH);
            FileOutputStream outFile =
                    new FileOutputStream(new File(String.format("%s\\%s_%s.xls", Constant.VALUATION_PATH, DateUtil.formatDate(DateUtil.date()), zsStockPool.getStrategy().getName())));
            workbook.write(outFile);
            outFile.close();
        }

    }

    @Override
    public void downloadValuationReportByCodes(String codes) throws IOException {
        List<String> codeList = Splitter.on(",").splitToList(codes);
        List<ValuationReport> reportList = Lists.newArrayList();
        List<ValuationReport> sortedList;
        codeList.stream().forEach(code -> {
            try {
                ZsStockInfo stockInfo = zsxgService.getStockInfo(code);
                ValuationReport valuationReport = convertFrom(stockInfo);
                if (valuationReport.getBuyPoint() != 0 && !valuationReport.getShowNetProfit().equals("--")) {
                    reportList.add(valuationReport);
                }
                log.info("valuationReport = {}",JSONObject.toJSONString(valuationReport));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        });
        sortedList = reportList.stream().sorted(Comparator.comparing(ValuationReport::getLocationBuyPoint)).collect(Collectors.toList());
        Workbook workbook = DefaultExcelBuilder.of(ValuationReport.class).build(sortedList);
        ToolsUtil.mkdir(Constant.VALUATION_PATH);
        FileOutputStream outFile =
                new FileOutputStream(new File(String.format("%s\\%s_%s.xls", Constant.VALUATION_PATH, DateUtil.formatDate(DateUtil.date()), "自定义股票池")));
        workbook.write(outFile);
        outFile.close();
    }

    private ValuationReport convertFrom(ZsStockInfo stockInfo) {
        ZsStockInfo.ForNetprofitBean netprofit = stockInfo.getForNetprofit();
        Double preNetProfit = 0D;
        String preNetProfitStr;
        String showNetProfit = "--";
        if (Objects.nonNull(netprofit) && netprofit.getValue().size() == 3) {
            Integer year = netprofit.getYear().get(2);
            preNetProfitStr = netprofit.getValue().get(2);
            if (!preNetProfitStr.equals("--")) {
                if(preNetProfitStr.contains(Constant.YI)) {
                    preNetProfit = Double.parseDouble(preNetProfitStr.replace(Constant.YI, ""));
                }
                showNetProfit = String.format("%s(%d)", preNetProfitStr, year);
            }
        }
        Double prePe = 0D;
        if(Objects.nonNull(stockInfo.getPepbMap())) {
            prePe = stockInfo.getPepbMap().getPeMid() > 20 ? 20 : stockInfo.getPepbMap().getPeMid();
        }
        Long preValuation = Math.round(preNetProfit * prePe);
        Integer buyPoint = Math.round(preValuation / 2);
        Double marketValue = stockInfo.getTotal_mv();
        Double locationBuyPoint = (marketValue - buyPoint)/buyPoint*100;

        return ValuationReport.builder()
                .code(stockInfo.getCode())
                .name(stockInfo.getName())
                .preNetProfit(preNetProfit)
                .showNetProfit(showNetProfit)
                .prePe(prePe)
                .preValuation(preValuation)
                .buyPoint(buyPoint)
                .marketValue(marketValue)
                .locationBuyPoint(Math.round(locationBuyPoint))
                .showLocationBuyPoint(String.valueOf(Math.round(locationBuyPoint)) + "%")
                .sellPoint(preValuation * 1.1)
                .build();
    }

    private void downLoadNoticeByUrl(String url, String noticeName, String stockName) {
        try {
            if(StringUtils.isNotBlank(url)) {
                String noticeFileName = String.format("%s.pdf", noticeName);
                String path = String.format("%s\\%s\\年报", Constant.COMPANY_PATH, StringUtils.deleteWhitespace(stockName));
                File noticeFile = new File(String.format("%s\\%s", path, noticeFileName));
                if (!noticeFile.exists()) {
                    Request request = new Request.Builder().url(url).build();
                    Response response = ToolsUtil.getClient().newCall(request).execute();
                    ToolsUtil.mkdir(path);
                    FileOutputStream outFile =
                            new FileOutputStream(noticeFile);
                    outFile.write(response.body().bytes());
                    outFile.close();
                }
                log.info("下载完成：noticeName = {}", noticeName);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }


}
